package com.example.demo.hk.ClientDemo;


import cc.eguid.FFmpegCommandManager.FFmpegManager;
import com.example.demo.hk.entity.Device;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.NativeLongByReference;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.io.*;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * Created by Hanlex.Liu on 2018/9/22 11:55.
 */


public class HCNetTools {
	private Logger logger = LoggerFactory.getLogger(getClass());
	static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;
	//static PlayCtrl playControl = PlayCtrl.INSTANCE;

	HCNetSDK.NET_DVR_DEVICEINFO_V30 m_strDeviceInfo;//设备信息
	HCNetSDK.NET_DVR_IPPARACFG m_strIpparaCfg;//IP参数
	HCNetSDK.NET_DVR_CLIENTINFO m_strClientInfo;//用户参数

	boolean bRealPlay;//是否在预览.
	String m_sDeviceIP;//已登录设备的IP地址

	NativeLong lUserID;//用户句柄
	NativeLong loadHandle;//下载句柄
	NativeLong lPreviewHandle;//预览句柄
	NativeLongByReference m_lPort;//回调预览时播放库端口指针

	FFmpegManager manager;//rstp转rmtp工具

	//FRealDataCallBack fRealDataCallBack;//预览回调函数实现
	public HCNetTools() {
		JPopupMenu.setDefaultLightWeightPopupEnabled(false);//防止被播放窗口(AWT组件)覆盖
		lUserID = new NativeLong(-1);
		lPreviewHandle = new NativeLong(-1);
		m_lPort = new NativeLongByReference(new NativeLong(-1));
		//fRealDataCallBack= new FRealDataCallBack();
	}

	/**
	 * 初始化资源配置
	 */
	public int initDevices() {
		boolean b = hCNetSDK.NET_DVR_Init();
		if (!b) {
			//初始化失败
			//throw new RuntimeException("初始化失败");
			System.out.println("初始化失败");
			return 1;
		}
		return 0;
	}

	/**
	 * 设备注册
	 *
	 * @param name     设备用户名
	 * @param password 设备登录密码
	 * @param ip       IP地址
	 * @param port     端口
	 * @return 结果
	 */
	public int deviceRegist(String name, String password, String ip, String port) {

		if (bRealPlay) {//判断当前是否在预览
			return 2;//"注册新用户请先停止当前预览";
		}
		if (lUserID.longValue() > -1) {//先注销,在登录
			hCNetSDK.NET_DVR_Logout_V30(lUserID);
			lUserID = new NativeLong(-1);
		}
		//注册(既登录设备)开始
		m_sDeviceIP = ip;
		short iPort = Integer.valueOf(port).shortValue();
		m_strDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();//获取设备参数结构
		lUserID = hCNetSDK.NET_DVR_Login_V30(ip, iPort, name, password, m_strDeviceInfo);//登录设备
		long userID = lUserID.longValue();
		if (userID == -1) {
			int iErr = hCNetSDK.NET_DVR_GetLastError();
			System.out.println("：注册失败,错误号：" + iErr);
			System.out.println(hCNetSDK.NET_DVR_GetErrorMsg(m_lPort));
			m_sDeviceIP = "";//登录未成功,IP置为空
			return 3;//"注册失败";
		}
		return 0;
	}

	/**
	 * 获取设备通道
	 */
	public int getChannelNumber() {
		IntByReference ibrBytesReturned = new IntByReference(0);//获取IP接入配置参数
		boolean bRet = false;
		int iChannelNum = -1;

		m_strIpparaCfg = new HCNetSDK.NET_DVR_IPPARACFG();
		m_strIpparaCfg.write();
		Pointer lpIpParaConfig = m_strIpparaCfg.getPointer();
		bRet = hCNetSDK.NET_DVR_GetDVRConfig(lUserID, HCNetSDK.NET_DVR_GET_IPPARACFG, new NativeLong(0), lpIpParaConfig, m_strIpparaCfg.size(), ibrBytesReturned);
		m_strIpparaCfg.read();

		String devices = "";
		if (!bRet) {
			//设备不支持,则表示没有IP通道
			for (int iChannum = 0; iChannum < m_strDeviceInfo.byChanNum; iChannum++) {
				devices = "Camera" + (iChannum + m_strDeviceInfo.byStartChan);
			}
		} else {
			for (int iChannum = 0; iChannum < HCNetSDK.MAX_IP_CHANNEL; iChannum++) {
				if (m_strIpparaCfg.struIPChanInfo[iChannum].byEnable == 1) {
					devices = "IPCamera" + (iChannum + m_strDeviceInfo.byStartChan);
				}
			}
		}
		if (StringUtils.isNotEmpty(devices)) {
			if (devices.charAt(0) == 'C') {//Camara开头表示模拟通道
				//子字符串中获取通道号
				iChannelNum = Integer.parseInt(devices.substring(6));
			} else {
				if (devices.charAt(0) == 'I') {//IPCamara开头表示IP通道
					//子字符创中获取通道号,IP通道号要加32
					iChannelNum = Integer.parseInt(devices.substring(8)) + 32;
				} else {
					return 4;
				}
			}
		}
		return iChannelNum;
	}

	public void shutDownDev() {
		//如果已经注册,注销
		if (lUserID.longValue() > -1) {
			hCNetSDK.NET_DVR_Logout_V30(lUserID);
		}
		hCNetSDK.NET_DVR_Cleanup();
	}


	/**
	 * 抓拍图片
	 *
	 * @param dvr
	 */
	public void getDVRPic(Device dvr, int chan, String imgpath) {
		NativeLong chanLong = new NativeLong(chan);

		if (!hCNetSDK.NET_DVR_Init()) {
			logger.warn("hksdk(抓图)-海康sdk初始化失败!");
			return;
		}
		HCNetSDK.NET_DVR_DEVICEINFO_V30 devinfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();// 设备信息
		//注册设备
		lUserID = hCNetSDK.NET_DVR_Login_V30(dvr.getIp(), Short.valueOf(dvr.getPort()), dvr.getAccount(), dvr.getPassword(), devinfo);// 返回一个用户编号，同时将设备信息写入devinfo

		if (lUserID.intValue() < 0) {
			logger.warn("hksdk(抓图)-设备注册失败,错误码:" + hCNetSDK.NET_DVR_GetLastError());
			return;
		}
		HCNetSDK.NET_DVR_WORKSTATE_V30 devwork = new HCNetSDK.NET_DVR_WORKSTATE_V30();
		if (!hCNetSDK.NET_DVR_GetDVRWorkState_V30(lUserID, devwork)) {
			// 返回Boolean值，判断是否获取设备能力
			logger.info("hksdk(抓图)-返回设备状态失败");
		}
		//图片质量
		HCNetSDK.NET_DVR_JPEGPARA jpeg = new HCNetSDK.NET_DVR_JPEGPARA();
		//设置图片分辨率
		jpeg.wPicSize = 5;
		//设置图片质量
		jpeg.wPicQuality = 0;
		IntByReference a = new IntByReference();
		//设置图片大小
		ByteBuffer jpegBuffer = ByteBuffer.allocate(1024 * 1024);
		//String jpegBuffer ="1024 * 1024";
		File file = new File(imgpath);
		// 抓图到内存，单帧数据捕获并保存成JPEG存放在指定的内存空间中
		//需要加入通道
		boolean is = hCNetSDK.NET_DVR_CaptureJPEGPicture_NEW(lUserID, chanLong, jpeg, jpegBuffer, 1024 * 1024, a);
		if (is) {
			logger.info("hksdk(抓图)-结果状态值(0表示成功):" + hCNetSDK.NET_DVR_GetLastError());
			//存储到本地
			BufferedOutputStream outputStream = null;
			try {
				outputStream = new BufferedOutputStream(new FileOutputStream(file));
				outputStream.write(jpegBuffer.array(), 0, a.getValue());
				outputStream.flush();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (outputStream != null) {
					try {
						outputStream.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		} else {
			logger.info("hksdk(抓图)-抓取失败,错误码:" + hCNetSDK.NET_DVR_GetLastError());
		}

		hCNetSDK.NET_DVR_Logout(lUserID);//退出登录
		//hcNetSDK.NET_DVR_Cleanup();
	}

	/* *
	 * @Description:  下载录像
	 * @param null
	 * @Return：
	 * @Author: miaozm
	 * @Date: 2020/4/7 14:50
	 */
	public boolean downloadVideo(Device dvr, Date startTime, Date endTime, String filePath, int channel) {
		boolean initFlag = hCNetSDK.NET_DVR_Init();
		if (!initFlag) { //返回值为布尔值 fasle初始化失败
			logger.warn("hksdk(视频)-海康sdk初始化失败!");
			return false;
		}
		HCNetSDK.NET_DVR_DEVICEINFO_V30 deviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();
		lUserID = hCNetSDK.NET_DVR_Login_V30(dvr.getIp(), Short.valueOf(dvr.getPort()), dvr.getAccount(), dvr.getPassword(), deviceInfo);
		logger.info("hksdk(视频)-登录海康录像机信息,状态值:" + hCNetSDK.NET_DVR_GetLastError());
		long lUserId = lUserID.longValue();
		if (lUserId == -1) {
			logger.warn("hksdk(视频)-海康sdk登录失败!");
			return false;
		}
		loadHandle = new NativeLong(-1);
		if (loadHandle.intValue() == -1) {
			loadHandle = hCNetSDK.NET_DVR_GetFileByTime(lUserID, new NativeLong(channel), getHkTime(startTime), getHkTime(endTime), filePath);
			logger.info("hksdk(视频)-获取播放句柄信息,状态值:" + hCNetSDK.NET_DVR_GetLastError());
			if (loadHandle.intValue() >= 0) {
				boolean downloadFlag = hCNetSDK.NET_DVR_PlayBackControl(loadHandle, hCNetSDK.NET_DVR_PLAYSTART, 0, null);
				int tmp = -1;
				IntByReference pos = new IntByReference();
				while (true) {
					boolean backFlag = hCNetSDK.NET_DVR_PlayBackControl(loadHandle, hCNetSDK.NET_DVR_PLAYGETPOS, 0, pos);
					if (!backFlag) {//防止单个线程死循环
						return downloadFlag;
					}
					int produce = pos.getValue();
					if ((produce % 10) == 0 && tmp != produce) {//输出进度
						tmp = produce;
						logger.info("hksdk(视频)-视频下载进度:" + "==" + produce + "%");
					}
					if (produce == 100) {//下载成功
						hCNetSDK.NET_DVR_StopGetFile(loadHandle);
						loadHandle.setValue(-1);
						hCNetSDK.NET_DVR_Logout(lUserID);//退出录像机
						logger.info("hksdk(视频)-退出状态" + hCNetSDK.NET_DVR_GetLastError());
						//hcNetSDK.NET_DVR_Cleanup();
						return true;
					}
					if (produce > 100) {//下载失败
						hCNetSDK.NET_DVR_StopGetFile(loadHandle);
						loadHandle.setValue(-1);
						logger.warn("hksdk(视频)-海康sdk由于网络原因或DVR忙,下载异常终止!错误原因:" + hCNetSDK.NET_DVR_GetLastError());
						//hcNetSDK.NET_DVR_Logout(userId);//退出录像机
						//logger.info("hksdk(视频)-退出状态"+hcNetSDK.NET_DVR_GetLastError());
						return false;
					}
				}
			} else {
				System.out.println("hksdk(视频)-下载失败" + hCNetSDK.NET_DVR_GetLastError());
				return false;
			}
		}
		return false;
	}


	/* *
	 * @Description:  获取录像文件信息
	 * @param null
	 * @Return：
	 * @Author: miaozm
	 * @Date: 2020/4/7 14:50
	 */
	public List getFileList(Device dvr, Date startTime, Date endTime, int channel) {
		List fileList = new ArrayList();
		boolean initFlag = hCNetSDK.NET_DVR_Init();
		if (!initFlag) { //返回值为布尔值 fasle初始化失败
			logger.warn("hksdk(视频)-海康sdk初始化失败!");
			//return null;
		}
		HCNetSDK.NET_DVR_DEVICEINFO_V30 deviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();
		lUserID = hCNetSDK.NET_DVR_Login_V30(dvr.getIp(), Short.valueOf(dvr.getPort()), dvr.getAccount(), dvr.getPassword(), deviceInfo);
		logger.info("hksdk(视频)-登录海康录像机信息,状态值:" + hCNetSDK.NET_DVR_GetLastError());
		long lUserId = lUserID.longValue();
		if (lUserId == -1) {
			logger.warn("hksdk(视频)-海康sdk登录失败!");
			//return null;
		}
		// 搜索条件
		HCNetSDK.NET_DVR_FILECOND m_strFilecond = new HCNetSDK.NET_DVR_FILECOND();
		m_strFilecond.struStartTime = getHkTime(startTime);
		m_strFilecond.struStopTime = getHkTime(endTime);
		m_strFilecond.lChannel = new NativeLong(channel);//通道号

		NativeLong lFindFile = hCNetSDK.NET_DVR_FindFile_V30(lUserID, m_strFilecond);
		HCNetSDK.NET_DVR_FINDDATA_V30 strFile = new HCNetSDK.NET_DVR_FINDDATA_V30();
		long findFile = lFindFile.longValue();
		if (findFile > -1) {
			System.out.println("file" + findFile);
		}
		NativeLong lnext;
		strFile = new HCNetSDK.NET_DVR_FINDDATA_V30();
		Map map = null;
		boolean flag=true;
		while (flag) {
			lnext = hCNetSDK.NET_DVR_FindNextFile_V30(lFindFile, strFile);
			if (lnext.longValue() == HCNetSDK.NET_DVR_FILE_SUCCESS) {
				//搜索成功
				map = new HashMap<>();
				//添加文件名信息
				String[] s = new String[2];
				s = new String(strFile.sFileName).split("\0", 2);
				map.put("fileName", new String(s[0]));

				int iTemp;
				String MyString;
				if (strFile.dwFileSize < 1024 * 1024) {
					iTemp = (strFile.dwFileSize) / (1024);
					MyString = iTemp + "K";
				} else {
					iTemp = (strFile.dwFileSize) / (1024 * 1024);
					MyString = iTemp + "M   ";
					iTemp = ((strFile.dwFileSize) % (1024 * 1024)) / (1204);
					MyString = MyString + iTemp + "K";
				}
				map.put("fileSize", MyString);                      //添加文件大小信息
				map.put("struStartTime", strFile.struStartTime.toStringTime());                      //添加开始时间信息
				map.put("struStopTime", strFile.struStopTime.toStringTime());                      //添加结束时间信息
				fileList.add(map);
			}else
			{
				if (lnext.longValue() == HCNetSDK.NET_DVR_ISFINDING)
				{//搜索中
					//System.out.println("搜索中");
					continue;
				}
				else
				{
					flag=false;
					if (lnext.longValue() == HCNetSDK.NET_DVR_FILE_NOFIND)
					{
						//flag=false;
					}
					else
					{
						//flag=false;
						System.out.println("搜索文件结束");
						boolean flag2 = hCNetSDK.NET_DVR_FindClose_V30(lFindFile);
						if (flag2 == false)
						{
							System.out.println("结束搜索失败");
						}
					}
				}
			}
		}
		return fileList;
	}

	/**
	 * 获取海康录像机格式的时间
	 *
	 * @param time
	 * @return
	 */
	public HCNetSDK.NET_DVR_TIME getHkTime(Date time) {
		HCNetSDK.NET_DVR_TIME structTime = new HCNetSDK.NET_DVR_TIME();
		String str = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(time);
		String[] times = str.split("-");
		structTime.dwYear = Integer.parseInt(times[0]);
		structTime.dwMonth = Integer.parseInt(times[1]);
		structTime.dwDay = Integer.parseInt(times[2]);
		structTime.dwHour = Integer.parseInt(times[3]);
		structTime.dwMinute = Integer.parseInt(times[4]);
		structTime.dwSecond = Integer.parseInt(times[5]);
		return structTime;
	}


}
